package main

import (
	"fmt"
	"time"
)

//&x是传递的指针，所以调用inc函数，会改变x的值
func inc(ch chan bool, x *int) {
	//当一个协程A执行这里后。就会尝试往信道里写数据。如果写不进去，就证明有另一个协程X正在处理 *x++ ，协程A就会阻塞一会。
	//等到协程X处理完后，就会把ch信道中的数据取出来。此时信道ch就腾出空位来了。协程A就能往信道里写入数据了，也就能继续执行下一行代码，即*x++
	//这样就能保证，每一个协程，都是在上一个协程的计算结果出来之后，再进行计算的
	ch <- true //作用是加锁,如果有其它协程正在处理，这里就会阻塞
	*x++
	<-ch //作用是释放锁
}

func incNoLock(x *int) {
	//没有锁的话，就不能保证，每一个协程会等上一个计算结果完成后，再去计算。
	*x++
}

func main() {
	//注意这里的容量，一定要设置为1
	pipeline := make(chan bool, 1)
	var x int
	for i := 0; i < 1000; i++ {
		//发起一个协程。这里循环1000次，就会创建1000个协程，同时执行这个任务。
		//因为是同时执行的，如何保证结果不会互相覆盖呢？答案就是加锁,多个协程共用一个信道来实现通信和加锁
		go inc(pipeline, &x)
	}

	var y int
	for i := 0; i < 1000; i++ {
		go incNoLock(&y)
	}
	fmt.Println("有锁，x 的值：", x)

	//y的值小于1000，证明发生了写入覆盖
	fmt.Println("无锁，y 的值：", y)
	time.Sleep(time.Second)
}
